﻿using System;
using System.Collections.Generic;
using System.Data;
using System.Reflection;

namespace AxeFrog.Data
{
	public static class DbTypeMapper
	{
		private static readonly Dictionary<Type, DbType> DbTypeMap = new Dictionary<Type, DbType>
		{
			{ typeof(Int16), DbType.Int16 },
			{ typeof(Int32), DbType.Int32 },
			{ typeof(Int64), DbType.Int64 },
			{ typeof(Single), DbType.Single },
			{ typeof(Double), DbType.Double },
			{ typeof(Decimal), DbType.Decimal },
			{ typeof(Byte), DbType.Byte },
			{ typeof(Byte[]), DbType.Binary },
			{ typeof(Boolean), DbType.Boolean },
			{ typeof(Char), DbType.StringFixedLength },
			{ typeof(string), DbType.String },
			{ typeof(DateTime), DbType.DateTime },
			{ typeof(TimeSpan), DbType.Int64 },
			{ typeof(Int16?), DbType.Int16 },
			{ typeof(Int32?), DbType.Int32 },
			{ typeof(Int64?), DbType.Int64 },
			{ typeof(Single?), DbType.Single },
			{ typeof(Double?), DbType.Double },
			{ typeof(Decimal?), DbType.Decimal },
			{ typeof(Byte?), DbType.Byte },
			{ typeof(Boolean?), DbType.Boolean },
			{ typeof(Char?), DbType.StringFixedLength },
			{ typeof(DateTime?), DbType.DateTime },
			{ typeof(TimeSpan?), DbType.Int64 },
			{ typeof(Type), DbType.String }
		};

		public static bool HasDbType(this Type type)
		{
			return DbTypeMap.ContainsKey(AdjustTypeForEnums(type));
		}

		public static DbType ToDbType(this Type type)
		{
			return DbTypeMap[AdjustTypeForEnums(type)];
		}

		private static Type AdjustTypeForEnums(Type type)
		{
			if(type.IsEnum)
				type = typeof(int);
			else
			{
				var ntype = Nullable.GetUnderlyingType(type);
				if(ntype != null && ntype.IsEnum)
					type = typeof(int);
			}
			return type;
		}

		public static void AssertHasDbType(this Type type)
		{
			if (!AdjustTypeForEnums(type).HasDbType())
				throw new Exception("Type " + type.FullName + " does not have a DbType mapping");
		}
	}
}
